package com.task.platform.service;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.task.platform.cache.MemoryCache;
import com.task.platform.exception.CustomException;
import com.task.platform.mapper.UserMapper;
import com.task.platform.bo.sys.po.User;
import com.task.platform.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImp extends ServiceImpl<UserMapper, User> implements UserService, UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private EmailService emailService;

    @Override
    public User findByUsername(String username) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return org.springframework.security.core.userdetails.User
                .withUsername(user.getUsername())
                .password(user.getPassword())
                .authorities("USER") // You can set roles or authorities here
                .build();
    }

    @Override
    @Transactional(rollbackFor = CustomException.class)
    public String register(User user) {
        if (findByUsername(user.getUsername()) != null) {
            throw new CustomException("Username already exists!");
        }
        if (findUserByEmail(user.getEmail()) != null) {
            throw new CustomException("Email already exists!");
        }
        String password = user.getPassword();
        user.setPassword(passwordEncoder.encode(password));
        save(user);
        user.setPassword(password);
        return emailService.verifyEmailCode(user.getEmail(), user.getVerifyCode());
    }

    @Override
    public User findUserByEmail(String email) {

        return userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
    }

    @Override
    public boolean save(User entity) {
        return super.save(entity);
    }


    @Override
    public String getJwt(User user) {
        User sysUser = findUserByEmail(user.getEmail());
        if (sysUser == null) {
            throw new CustomException("User not found!");
        }

        try {
            // 使用 Spring Security 的 AuthenticationManager 进行身份验证
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getEmail(), user.getPassword());
            Authentication authentication = authenticationManager.authenticate(authenticationToken);

            // 设置认证信息到安全上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 生成 JWT token
            UserDetails principal = (UserDetails) authentication.getPrincipal();
            String jwt = jwtUtil.generateToken((principal.getUsername()));
            return jwt;
        } catch (AuthenticationException e) {
            throw new CustomException("Invalid username or password!");
        }
    }

    @Override
    public String getJwt(User user, String verificationCode) {
        User sysUser = findUserByEmail(user.getEmail());
        if (sysUser == null) {
            throw new CustomException("User not found!");
        }

        // 验证验证码
        String cachedCode = (String) MemoryCache.getInstance().get(user.getEmail());
        if (cachedCode == null || !cachedCode.equals(verificationCode)) {
            throw new CustomException("Invalid or expired verification code!");
        }

        // 如果通过验证码验证，则认为用户已被认证，可以生成 JWT
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken(sysUser.getUsername(), null, new ArrayList<>())
        );

        // 生成 JWT token
        String jwt = jwtUtil.generateToken(sysUser.getUsername());

        // 清除验证码缓存
        MemoryCache.getInstance().remove(user.getEmail());
        return jwt;
    }

    @Override
    public void batchRegister(List<User> users) {
        List<Map<String, String>> list = new ArrayList<>();
        for (User user : users) {
            if (findByUsername(user.getUsername()) != null) {
                continue;
            }
            if (findUserByEmail(user.getEmail()) != null) {
                continue;
            }
            String password = RandomUtil.randomNumbers(6);
            user.setPassword(passwordEncoder.encode(password));
            save(user);
            Map<String, String> map = new HashMap<>();
            map.put("email", user.getEmail());
            map.put("password", password);
            list.add(map);
        }
        for (Map<String, String> user : list) {
            try {
                String text = buildText(user);
                emailService.sendSimpleRegisterEmail(user.get("email"), text);
            } catch (Exception e) {
                log.error("Failed to send email to user: " + user.get("email"), e);
            }
        }
    }

    private String buildText(Map<String, String> user) {
        return "Congratulations on successfully registering. Your login account is: " + user.get("email") + ", and your login password is: " + user.get("password");
    }


}
